﻿using OSGeo.GDAL;
using OSGeo.OGR;
using RemoteSensingImageDirectServer.Untils.ScopeSpace;
using System.Runtime.CompilerServices;

namespace RemoteSensingImageDirectServer.Untils.Extensions
{
    public static class GdalExtensions
    {
        private static string[] BurnMaskBandOptions = new string[] { "ALL_TOUCHED", "TRUE" };
        /// <summary>
        /// 获取栅格的范围以及分辨率
        /// </summary>
        /// <param name="ds"></param>
        /// <returns></returns>
        public static RasterEnvelope GetRasterEnvelope(this Dataset ds)
        {
            int nImgSizeX = ds.RasterXSize; //获取横向像元个数
            int nImgSizeY = ds.RasterYSize; //获取纵向像元个数

            double[] adfGeoTransform = new double[6];//获取影像的参数
            ds.GetGeoTransform(adfGeoTransform);
            // 0 X;    1 imagewidth;     2 0;   3 Y;   4 0;     5 imageheight

            //右下角坐标    
            double ImgdrX = adfGeoTransform[0] + nImgSizeX * adfGeoTransform[1];
            double ImgdrY = adfGeoTransform[3] + nImgSizeY * adfGeoTransform[5];

            return new RasterEnvelope(
                adfGeoTransform[0], ImgdrY, ImgdrX, adfGeoTransform[3],
                adfGeoTransform[1], adfGeoTransform[5]);
        }

        /// <summary>
        /// 获取数据的经纬度范围
        /// </summary>
        /// <param name="ds">数据dataset</param>
        /// <param name="callback">回调函数</param>
        /// <returns></returns>
        public static RasterEnvelope GetWGS84RasterEnvelope(this Dataset ds, Gdal.GDALProgressFuncDelegate? callback = null)
        {

            Dataset[] datasetArray = new Dataset[1];
            datasetArray[0] = ds;

            //取一个唯一随机值,并注册虚拟内存
            var warpFilename = $"/vsimem/{Guid.NewGuid().ToString()}.vrt";

            //将warp变换的成果写入到虚拟内存中
            var warpDs = Gdal.Warp(warpFilename, datasetArray,
                new GDALWarpAppOptions(new string[] { "-t_srs", $"EPSG:4326", "-overwrite", "-r", "nearest" }),
                callback, $"project");

            //获取四至范围
            var rasterEnv = warpDs.GetRasterEnvelope();

            warpDs.Free();

            //释放虚拟内存中的数据
            Gdal.Unlink(warpFilename);

            //返回范围
            return rasterEnv;

        }


        /// <summary>
        /// 设置影像的四至范围
        /// </summary>
        /// <param name="ds">数据集</param>
        /// <param name="env">范围</param>
        public static void SetRasterEnvelope(this Dataset ds, RasterEnvelope env)
        {
            var geo = new double[] { env.MinX, env.ResolutionX, 0, env.MaxY, 0, env.ResolutionY };
            ds.SetGeoTransform(geo);
        }


        /// <summary>
        /// 生成掩膜区域
        /// </summary>
        /// <param name="ds">数据集</param>
        /// <param name="mask_file">掩膜文件</param>
        /// <param name="bandCount">原始读取数据波段数量</param>
        /// <param name="options">扩展参数</param>
        /// <returns>返回一个掩膜区域的二进制数组</returns>
        public static byte[] BurnMask(this Dataset ds, Layer maskLayer, int bandCount, string[] options = null)
        {
            var imageXSize = ds.RasterXSize;
            var imageYSize = ds.RasterYSize;

            double nodata = 0, dburnValue = 255.0;
            if (bandCount == 1)
            {
                nodata = 255.0;
                dburnValue = 0;
            }
            ds.GetRasterBand(1).Fill(nodata, nodata);

            var maskArr = Enumerable.Repeat((byte)dburnValue, imageXSize * imageYSize).ToArray();

            int[] pnbandlist = { 1 };
            double[] dburnValues = { dburnValue };
            options = options ?? BurnMaskBandOptions;

        burn:
            try
            {
                int status = Gdal.RasterizeLayer(ds,
                    1, pnbandlist, maskLayer, IntPtr.Zero, IntPtr.Zero,
                    1, dburnValues, options, null, null);
                //ds.FlushCache();

                if (status == 0)
                {
                    ds.GetRasterBand(1). ReadRaster( 0, 0, imageXSize, imageYSize,maskArr, imageXSize, imageYSize, 0, 0);
                }

                return maskArr;
            }
            catch
            {
                goto burn;
            }
        }

        /// <summary>
        /// 释放此数据集
        /// </summary>
        /// <param name="ds"></param>
        public static void Free(this Dataset ds)
        {
            if (ds == null) return;

            //ds.Close();
            ds.Dispose();
        }

        /// <summary>
        /// 释放此数据集列表
        /// </summary>
        /// <param name="ds"></param>
        public static void Free(this Dataset[] datasets)
        {
            foreach (var ds in datasets)
            {
                ds.Free();
            }
        }

        /// <summary>
        /// 释放此数据集列表
        /// </summary>
        /// <param name="ds"></param>
        public static void Free(this List<Dataset> datasets)
        {
            foreach (var ds in datasets)
            {
                if (ds == null) continue;
                ds.Free();
            }
        }
    }
}
